package com.googlecode.economini.issues.task;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import org.xml.sax.SAXException;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.database.Cursor;
import android.net.Uri;

import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.googlecode.economini.converter.IssueConverter;
import com.googlecode.economini.converter.IssueToken;
import com.googlecode.economini.converter.Token;
import com.googlecode.economini.issues.IssueProvider;
import com.googlecode.economini.issues.IssueStore;

public class LoadIssueTask implements Callable<Object> {

  private final ListeningExecutorService executor;
  private final ContentResolver resolver;
  private final long issueId;

  public LoadIssueTask(
      ListeningExecutorService executor,
      ContentResolver resolver,
      long issueId) {
    this.executor = executor;
    this.resolver = resolver;
    this.issueId = issueId;
  }

  @Override
  public Object call() throws Exception {
    Uri issueUri = ContentUris.withAppendedId(IssueProvider.ISSUE_URI, issueId);
    Cursor issue = resolver.query(
        issueUri, new String[] { IssueStore.URL_COLUMN }, null, null, null);

    if (!issue.moveToNext()) {
      throw new IllegalArgumentException(Long.toString(issueId)
          + " is not a valid issue ID");
    }

    InputStream inputStream = new URL(
        "http://www.economist.com" + issue.getString(0)).openStream();
    try {
      // TODO make "article" constant
      processIssue(inputStream, Uri.withAppendedPath(issueUri, "article"));
    } finally {
      inputStream.close();
    }

    return null;
  }

  private void processIssue(InputStream inputStream, Uri issueUri)
      throws IOException, SAXException {
    IssueConverter converter = IssueConverter.newInstance();

    List<Token<IssueToken>> tokenList = converter.parse(
        new BufferedInputStream(inputStream));

    String section = "";
    Map<IssueToken, String> values = Maps.newEnumMap(IssueToken.class);
    for (Token<IssueToken> token : tokenList) {
      // One section for multiple articles
      if (token.getType() == IssueToken.SECTION_TITLE) {
        section = token.getValue();
        continue;
      }

      // When encountering a previously seen key, write out all keys
      if (values.containsKey(token.getType())) {
        loadArticle(issueUri, section, values);
        // Reset the values for subsequent runs
        values.clear();
      }

      values.put(token.getType(), token.getValue());
    }

    // Write outstanding values, if any
    if (!values.isEmpty()) {
      loadArticle(issueUri, section, values);
    }
  }

  private void loadArticle(
      Uri issueUri,
      String section,
      Map<IssueToken, String> values) {
    executor.submit(new LoadArticleTask(
        resolver,
        issueUri,
        issueId,
        section,
        values.get(IssueToken.ARTICLE_URL),
        values.get(IssueToken.ARTICLE_TITLE)));
  }
}
